﻿using System;
using System.Data.Odbc;

namespace Centido.Core
{
    /// <summary>
    ///   A set of table column read operations.
    /// </summary>
    public static class ColumnReadOperations
    {
        /// <summary>
        ///   Reads the data in the column of the specified row from the specified data source.
        /// </summary>
        /// <param name="column">The target table column.</param>
        /// <param name = "rowId">The id of the specified row.</param>
        /// <param name = "dataSource">The specified data source.</param>
        /// <returns>Returns the value in the column if the specified row exists; otherwise, null.</returns>
        private static ColumnValue ReadImplementation(Column column, 
            Guid rowId, DataSource dataSource)
        {
            var tableName = column.GetDataSourceName(dataSource);

            var resultValue = column.EmptyValue();

            column.Domain.DbAccess.ExecuteScalar(
                cmd =>
                {
                    cmd.CommandText = string.Format(
                        "select {0} from {1} where {2}=?",
                        column.Name,
                        tableName,
                        Db.Tables.UserTable.Col.Id);

                    cmd.Parameters.Add(column.Domain.DbAccess.CreateParameter(
                        "id", OdbcType.Binary, rowId.ToByteArray()));
                },
                result => resultValue = column.Value(result));

            return resultValue;
        }


        /// <summary>
        ///   Reads data in the column of the specified row.
        /// </summary>
        /// <remarks>The current user has to have the select permission on the table in order to execute this function.</remarks>
        /// <param name="column">The target table column.</param>
        /// <param name = "rowId">The id of the specified row.</param>
        /// <returns>Returns the value in the column if the specified row exists; otherwise, null.</returns>
        /// <exception cref="System.Data.Common.DbException">Thrown when the current user has no permission to execute this function.</exception>
        /// <example>
        ///   The following example shows how to read data in the column.
        /// <code>
        ///     using System;
        ///     using Centido.Core;
        /// 
        ///     class Sample
        ///     {
        ///         static void Main()
        ///         {
        ///             var domainConfig = new DomainConfiguration()
        ///             {
        ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
        ///                 DbProviderName = "MSSQLSERVER"
        ///             };
        ///         
        ///             var domain = Domain.Build(domainConfig);
        ///         
        ///             domain.DeleteAll();
        ///             
        ///             //Adding a new table
        ///             var table = domain.AddTable("my_table");
        /// 
        ///             //Adding two columns
        ///             var firstColumn = table.AddColumn("first_column", ColumnType.String);
        ///             var secondColumn = table.AddColumn("second_column", ColumnType.Integer);
        /// 
        ///             //Granting all necessary permissions
        ///             table.GrantAll();
        /// 
        ///             //Inserting a row
        ///             var id = table.InsertRow(firstColumn.Value("My value"), secondColumn.Value(1));
        /// 
        ///             //Reading inserted values
        ///             Console.WriteLine("Row: first column = {0}, second column = {1}",
        ///                 firstColumn.Read(id).GetString(),
        ///                 secondColumn.Read(id).GetInteger());
        ///         }
        ///     }
        /// </code>
        /// </example>
        public static ColumnValue Read(this Column column, Guid rowId)
        {
            if (column == null)
                throw new ArgumentNullException("column");

            return ReadImplementation(column, rowId, DataSource.UserView);
        }


        /// <summary>
        ///   Reads data in the column of the specified row from the specified data source.
        /// </summary>
        /// <remarks>The current user has to have the select permission on the table in order to execute this function
        /// if the data source is the user view of the table. And the current user has to have the permission
        /// to change the schema if the data source is the internal table.</remarks>
        /// <param name="column">The target table column.</param>
        /// <param name = "rowId">The id of the specified row.</param>
        /// <param name = "dataSource">The specified data source.</param>
        /// <returns>Returns the value in the column if the specified row exists; otherwise, null.</returns>
        /// <exception cref="System.Data.Common.DbException">Thrown when the current user has no permission to execute this function.</exception>
        /// <example>
        ///   The following example shows how to read data in the column from the internal table.
        /// <code>
        ///     using System;
        ///     using Centido.Core;
        /// 
        ///     class Sample
        ///     {
        ///         static void Main()
        ///         {
        ///             var domainConfig = new DomainConfiguration()
        ///             {
        ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
        ///                 DbProviderName = "MSSQLSERVER"
        ///             };
        ///         
        ///             var domain = Domain.Build(domainConfig);
        ///         
        ///             domain.DeleteAll();
        ///             
        ///             //Adding a new table
        ///             var table = domain.AddTable("my_table");
        /// 
        ///             //Adding two columns
        ///             var firstColumn = table.AddColumn("first_column", ColumnType.String);
        ///             var secondColumn = table.AddColumn("second_column", ColumnType.Integer);
        /// 
        ///             //Granting all necessary permissions
        ///             table.GrantAll();
        /// 
        ///             //Inserting a row
        ///             var id = table.InsertRow(firstColumn.Value("My value"), secondColumn.Value(1));
        /// 
        ///             //Reading inserted values
        ///             Console.WriteLine("Row: first column = {0}, second column = {1}",
        ///                 firstColumn.Read(id, DataSource.InternalTable).GetString(),
        ///                 secondColumn.Read(id, DataSource.InternalTable).GetInteger());
        ///         }
        ///     }
        /// </code>
        /// </example>
        public static ColumnValue Read(this Column column, Guid rowId, DataSource dataSource)
        {
            if (column == null)
                throw new ArgumentNullException("column");

            return ReadImplementation(column, rowId, dataSource);
        }
    }
}
